using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections;
using System.Reflection;

namespace BTVPodcatcherNamespace
{
    public class SortableSearchableList<T> : BindingList<T>
    {
        public SortableSearchableList()
        {

        }
        protected override void InsertItem(int index, T item)
        {
            base.InsertItem(index, item);
            if (sortPropertyValue != null && index > 0
                && index == this.Count - 1)
                ApplySortCore(this.sortPropertyValue, this.sortDirectionValue);
        } 

        public override void EndNew(int itemIndex)
        {
            
            if (sortPropertyValue != null && itemIndex > 0
                && itemIndex == this.Count - 1)
                ApplySortCore(this.sortPropertyValue, this.sortDirectionValue);
            base.EndNew(itemIndex);


        }
        
        protected override void OnAddingNew(AddingNewEventArgs e)
        {
            
            if(unsortedItems!= null)
            {

                unsortedItems.Add((T)e.NewObject);
            }
            base.OnAddingNew(e);
        }
        ListSortDirection sortDirectionValue;
        PropertyDescriptor sortPropertyValue;

        protected override PropertyDescriptor SortPropertyCore
        {
            get { return sortPropertyValue; }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get { return sortDirectionValue; }
        }

        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        public void RemoveSort()
        {
            RemoveSortCore();
        }

        
        List<T> unsortedItems;

        protected override void ApplySortCore(PropertyDescriptor prop,
            ListSortDirection direction)
        {
            
            

            // Check to see if the property type we are sorting by implements
            // the IComparable interface.
            Type interfaceType = prop.PropertyType.GetInterface("IComparable");
            
            
            if (interfaceType != null)
            {
                List<searchedClass<T>> sortList = new List<searchedClass<T>>(this.Count);
                RemoveSortCore();
                // If so, set the SortPropertyValue and SortDirectionValue.
                sortPropertyValue = prop;
                sortDirectionValue = direction;
                bool createUnsortedList = false;
                if (unsortedItems == null || unsortedItems.Count != this.Count)
                {
                    unsortedItems = new List<T>();
                    createUnsortedList = true;
                }


                // Loop through each item, adding it the the sortedItems ArrayList.
                foreach (object item in Items)
                {
                    sortList.Add(new searchedClass<T>((T)item,(IComparable) prop.GetValue(item)));
                    
                    if (createUnsortedList)
                        unsortedItems.Add((T)item);
                }
                sortList.Sort();

                if (direction == ListSortDirection.Descending)
                    sortList.Reverse();

                for (int i = 0; i < this.Count; i++)
                {
                    this[i] = sortList[i].mainObject;
                }
                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

            }
            else
                // If the property type does not implement IComparable, let the user
                // know.
                throw new NotSupportedException("Cannot sort by " + prop.Name + ". This" +
                    prop.PropertyType.ToString() + " does not implement IComparable");

        }

        protected override void RemoveSortCore()
        {
            int position;
            object temp;
            // Ensure the list has been sorted.
            if (unsortedItems != null)
            {
                

                // Loop through the unsorted items and reorder the
                // list per the unsorted list.
                for (int i = 0; i < unsortedItems.Count; )
                {

                    position = this.IndexOf(unsortedItems[i]); /*this.Find(SortPropertyCore.Name,
                        unsortedItems[i].GetType().
                        GetProperty(SortPropertyCore.Name).
                        GetValue(unsortedItems[i], null));*/
                    if (position >= 0 && position != i)
                    {
                        temp = this[i];
                        this[i] = this[position];
                        this[position] = (T)temp;
                        i++;
                    }
                    else if (position == i)
                        i++;
                    else
                        // If an item in the unsorted list no longer exists, delete it.
                        unsortedItems.RemoveAt(i);
                }
                unsortedItems = null;
                
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
                
            }
        }

        protected override bool SupportsSearchingCore
        {
            get
            {
                return true;
            }
        }

        protected override int FindCore(PropertyDescriptor prop, object key)
        {
            // Get the property info for the specified property.
            PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
            T item;

            if (key != null)
            {
                // Loop through the the items to see if the key
                // value matches the property value.
                for (int i = 0; i < Count; ++i)
                {
                    item = (T)Items[i];
                    if (propInfo.GetValue(item, null).Equals(key))
                        return i;
                }
            }
            return -1;
        }

        public int Find(string property, object key)
        {
            // Check the properties for a property with the specified name.
            PropertyDescriptorCollection properties =
                TypeDescriptor.GetProperties(typeof(T));
            PropertyDescriptor prop = properties.Find(property, true);

            // If there is not a match, return -1 otherwise pass search to
            // FindCore method.
            if (prop == null)
                return -1;
            else
                return FindCore(prop, key);
        }
    }

    public class searchedClass<T> : IComparable<searchedClass<T>>
    {
        T _mainObject;
        IComparable _searchingObject;
        public searchedClass(T main, IComparable  serach)
        {
            _mainObject = main;
            _searchingObject = serach;
        }

        public T mainObject
        {
            get
            {
                return _mainObject;
            }
        }
        public IComparable searchingObject
        {
            get
            {
                return _searchingObject;
            }
        }

        

        #region IComparable<searchedClass<T>> Members

        public int CompareTo(searchedClass<T> other)
        {
            return _searchingObject.CompareTo(other.searchingObject);
        }

        #endregion
    }
    
}
